package com.fiona.core.load;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fiona.annotation.FionaValue;
import com.fiona.annotation.FionaWrite;
import com.fiona.common.base.config.FionaConfig;
import com.fiona.core.model.FionaBeanModel;
import com.fiona.core.util.FionaConfiguration;

/**
 * 属性注入
 */
public class WriteFields {

    private static Logger log = LoggerFactory.getLogger(WriteFields.class);

    /**
     * 属性注入
     *
     * @param cls             需要注入属性的类
     * @param obj             需要注入属性的对象
     * @param fionaBeanObjects 要被注入的对象集合
     * @throws Exception 异常
     */
    public static void writeFields(Class cls, Object obj, Map<String, FionaBeanModel> fionaBeanObjects) throws Exception {
        FionaConfig config = FionaConfiguration.getConfig();

        Field[] fields = cls.getDeclaredFields();
        for (Field f : fields) {
            FionaWrite fionaWrite = f.getAnnotation(FionaWrite.class);
            FionaValue fionaValue = f.getAnnotation(FionaValue.class);
            if (fionaWrite != null && fionaValue != null) {
                throw new Exception("属性不可以同时有FionaWrite和FionaValue注解,类名:" + cls.getName());
            }

            doWrite(f,cls,obj,fionaBeanObjects,fionaWrite);
            doValue(f,cls,obj,config,fionaValue);
        }
    }

    /**
     * 给属性注入值
     * @param field 字段
     * @param cls 类
     * @param obj 对象
     * @param fionaBeanObjects bean对象集合
     * @param fionaWrite 注解
     * @throws Exception 异常
     */
    private static void doWrite(Field field,Class cls,Object obj,Map<String, FionaBeanModel> fionaBeanObjects,FionaWrite fionaWrite) throws Exception {
        if(fionaWrite == null){
            return;
        }
        String filedName = LoadHelper.getResourceName(fionaWrite, field);
        FionaBeanModel beanModel = fionaBeanObjects.get(filedName);
        if (beanModel != null) {
            field.setAccessible(true);
            field.set(obj, beanModel.getObj());
            log.info(cls.getName() + "的属性" + field.getName() + "注入成功");
        } else {
            throw new Exception("不存在name为" + filedName + "的FionaBean");
        }
    }

    /**
     * 给加了FionaValue注解的的属性注入值
     * @param field 字段
     * @param cls 类
     * @param obj 对象
     * @param fionaValue 注解
     * @throws Exception 异常
     */
    private static void doValue(Field field,Class cls,Object obj, FionaConfig config, FionaValue fionaValue) throws Exception {
        if(fionaValue == null){
            return;
        }
        if (!field.getType().equals(String.class)) {
            throw new Exception("FionaValue只能给String类型的属性注入值,类名:" + cls.getName());
        }
        field.setAccessible(true);
        String value = fionaValue.value();
        Object filedValue = getValue(value,config);
        if (filedValue == null) {
            throw new Exception("无法给属性注入:" + value);
        }

        field.set(obj, filedValue.toString());
        log.info(cls.getName() + "的属性" + field.getName() + "注入成功");
    }

    /**
     * 从配置中获取要注入的值
     *
     * @param value 名称
     * @return 值
     * @throws Exception 异常
     */
    private static Object getValue(String value,FionaConfig config) throws Exception {
        Properties fionaValues = config.getConfig();
        if(fionaValues == null){
            return null;
        }
        return fionaValues.get(value);
    }
}
